#include "Hand.h"


Hand::Hand(void)
{
	pair1Pos = -1;
	pair2Pos = -1;
	threeKindPos = -1;
	fourKindPos = -1;
}
Hand::~Hand(void)
{
}

void Hand::Sort() // sort list card order by face
{
	int min = 0;
	for(int i = 0; i < cardList.size() - 1; i++)
		for(int j = i+1;j < cardList.size(); j++)
		{
			if(cardList[i].CompareTo(cardList[j]) == 1)
			{
				Swap(cardList[i], cardList[j]);
			}
		}
}

int Hand::CountNumPair() // count number of pairs
{
	if(isFourKind() == true)
		return 0;
	else if(isThreeKind() == true)
	{
		if(threeKindPos == 0)
		{
			if(cardList[3].CompareTo(cardList[4]) == 0)
				return 1;
			else 
				return 0;
		}else if(threeKindPos == 2)
		{
			if(cardList[0].CompareTo(cardList[1]) == 0)
				return 1;
			else 
				return 0;
		}
		else
			return 0;
	}
	else
	{
		int pairs  = 0;
		for(int i = 0; i < cardList.size() - 1; i++)
		{
			if(cardList[i].CompareTo(cardList[i+1]) == 0)
			{
				pairs = pairs+1;
				if(pairs == 1){
					pair1Pos = i;
				}
				else
				{
					pair2Pos = i;
				}
			}
		}
		return pairs;
	}
}
bool Hand::isFourKind() // check is four kind
{
	if(cardList[0].CompareTo(cardList[3]) == 0)
	{
		fourKindPos = 0;
		return true;
	}
	else if(cardList[1].CompareTo(cardList[4]) == 0)
	{
		fourKindPos = 1;
		return true;
	}
	else
		return false;
}
bool Hand::isThreeKind() // check is three kind
{
	if(cardList[0].CompareTo(cardList[2]) == 0)
	{
		threeKindPos = 0;
		return true;
	}
	else if(cardList[1].CompareTo(cardList[3]) == 0)
	{
		threeKindPos = 1;
		return true;
	}
	else if(cardList[2].CompareTo(cardList[4]) == 0)
	{
		threeKindPos = 2;
		return true;
	}
	else
		return false;
}
bool Hand::isFlush() // is flush of not
{ 
	for(int i = 0; i < cardList.size()-1; i++)
	{
		if(cardList[i].IsSamSuit(cardList[i+1]) == false)
			return false;
	}
	return true;
}
bool Hand::isStraight() // is straight or not
{
	if((cardList[4].GetFace() - cardList[0].GetFace()) == 4 && this->CountNumPair() == 0 && this->isFourKind() == false && this->isThreeKind() == false)
		return true;
	return false;
}
int Hand::CountPoint() // return result of a hand . ex: three kind, straight,...
{
	int pairs = CountNumPair();
	if(isStraight()== true && isFlush() == true && cardList[4].GetFace() == 13)
		return 10; // royal flush
	else if(isStraight()== true && isFlush() == true)
		return 9; // Straight flush
	else if(isFourKind() == true)
		return 8; //four of a kind 
	else if(isThreeKind() == true && pairs == 1)
		return 7; // full house
	else if(isFlush() == true)
		return 6; // flush
	else if(isStraight() == true)
		return 5; // straight
	else if(isThreeKind() == true)
		return 4; // three of a kind
	else if(pairs == 2)
		return 3; // 2 pairs
	else if(pairs == 1)
		return 2; // 1 pair
	else
		return 1;	// high card

}
int Hand::CompareTo(Hand hand) // compare between 2 hands
{
	int myPoint = CountPoint();
	int otherPoint = hand.CountPoint();
	if(myPoint > otherPoint)
		return 1;
	else if(myPoint < otherPoint)
		return -1;
	else
	{
		switch(myPoint)
		{
			case 1:
				if(cardList[4].GetFace() > hand.getCardList()[4].GetFace())
					return 1;
				else if(cardList[4].GetFace() < hand.getCardList()[4].GetFace())
					return -1;
				else return 0;
				break;
			case 2:
				if(cardList[pair1Pos].GetFace() > hand.getCardList()[hand.GetPair1Pos()].GetFace())
					return 1;
				else if(cardList[pair1Pos].GetFace() < hand.getCardList()[hand.GetPair1Pos()].GetFace())
					return -1;
				else 
					return 0;
				break;
			case 3:
				if(cardList[pair2Pos].GetFace() > hand.getCardList()[hand.GetPair2Pos()].GetFace())
					return 1;
				else if(cardList[pair2Pos].GetFace() < hand.getCardList()[hand.GetPair2Pos()].GetFace())
					return -1;
				else 
					return 0;
				break;
			case 5:
				if(cardList[4].GetFace() > hand.getCardList()[4].GetFace())
					return 1;
				else if(cardList[4].GetFace() < hand.getCardList()[4].GetFace())
					return -1;
				else return 0;
				break;
			case 6:
				if(cardList[4].GetFace() > hand.getCardList()[4].GetFace())
					return 1;
				else if(cardList[4].GetFace() < hand.getCardList()[4].GetFace())
					return -1;
				else return 0;
				break;	
			case 7:
				if(cardList[threeKindPos].GetFace() > hand.getCardList()[hand.GetThreeKindPos()].GetFace())
					return 1;
				else if(cardList[threeKindPos].GetFace() < hand.getCardList()[hand.GetThreeKindPos()].GetFace())
					return -1;
				else 
					return 0;
				break;
			case 9:
				if(cardList[4].GetFace() > hand.getCardList()[4].GetFace())
					return 1;
				else if(cardList[4].GetFace() < hand.getCardList()[4].GetFace())
					return -1;
				else return 0;
				break;
			default:
				return 0;
		}
	}

}
void Hand::Swap(Card &card1, Card &card2)
{
	Card temp;
    std::memcpy (&temp, &card1, sizeof(Card));
    std::memcpy (&card1, &card2, sizeof(Card));
    std::memcpy (&card2, &temp, sizeof(Card));
}
void Hand::RemoveCards(vector<int> index) // remove number of cards in hand
{
	if (index.size() > 0)
	{
		vector<Card> lst = vector<Card>();
		bool isSame;
		for (int i = 0; i < this->cardList.size(); i++)
		{
			isSame = false;
			for (int j = 0; j < index.size(); j++)
			{
				if (i == index[j])
				{
					isSame = true;
					break;
				}
			}
			if (!isSame)
				lst.push_back(this->cardList[i]);
		}
		this->cardList = lst;
	}
}
void Hand::Print()
{
	for(int i = 0; i < cardList.size(); i++)
	{
		cout << cardList[i].toString() << endl;
	}
}
string Hand::toString()
{
	string str = "";
	for(int i = 0; i < cardList.size(); i++)
	{
		str += cardList[i].toString() + "\n";
	}
	return str;
}
int Hand::getIndexOfFirstPair()
{
	return this->pair1Pos;
}
int Hand::getIndexOfSecondPair()
{
	return this->pair2Pos;
}
int Hand::getIndexOfThreeKind()
{
	return this->threeKindPos;
}
int Hand::getIndexOfFourKind()
{
	return this->fourKindPos;
}
Card Hand::getCardByIndex(int index)
{
	if (0 <= index && index <= 4)
		return this->cardList[index];
	
	return Card(0,1);
}
